/*
 * Date：10/23/18 10:15 PM
 * Author: guomw
 *
 */

package org.elanfox.intellicommunity.biz.service.core.equipment.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.elanfox.intellicommunity.biz.dto.condition.CardCondition;
import org.elanfox.intellicommunity.biz.dto.equipment.CardSaveDTO;
import org.elanfox.intellicommunity.biz.dto.redis.RedisCardDTO;
import org.elanfox.intellicommunity.biz.entity.equipment.CardPO;
import org.elanfox.intellicommunity.biz.entity.equipment.CardPO_;
import org.elanfox.intellicommunity.biz.repository.equipment.CardRepository;
import org.elanfox.intellicommunity.biz.service.core.equipment.CardService;
import org.elanfox.intellicommunity.common.constant.ExcelConstant;
import org.elanfox.intellicommunity.common.constant.RedisConstant;
import org.elanfox.intellicommunity.common.ienum.CardEnum;
import org.elanfox.intellicommunity.common.ienum.base.CodeDescEnumHelper;
import org.elanfox.intellicommunity.common.utils.ExcelHelper;
import org.elanfox.intellicommunity.data.base.base.AbstractSearchableCrudService;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 卡相关service
 *
 * @author loutianxi
 * @date 2019-12-05
 */
@Service
public class CardServiceImpl extends AbstractSearchableCrudService<CardPO, Integer> implements CardService {

    @Autowired
    private CardRepository repository;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    protected CardServiceImpl(CardRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<CardPO> specificationAndSort(BaseSearchDTO condition) {
        CardCondition cardCondition = (CardCondition) condition;
        Specification<CardPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.isFalse(root.get(CardPO_.deleteStatus)));
            if (StringUtils.isNotEmpty(cardCondition.getCardNo())) {
                predicates.add(cb.equal(root.get(CardPO_.cardNo), cardCondition.getCardNo()));
            }
            if (cardCondition.getType() != -1) {
                CardEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(CardEnum.TypeEnum.class, cardCondition.getType());
                predicates.add(cb.equal(root.get(CardPO_.type), type));
            }
            if (cardCondition.getEnable() != null) {
                predicates.add(cb.equal(root.get(CardPO_.enable), cardCondition.getEnable()));
            }
            if (cardCondition.getStatus() != null) {
                predicates.add(cb.equal(root.get(CardPO_.status), cardCondition.getStatus()));
            }
            if (cardCondition.getVoltageStatus() != null) {
                CardEnum.VoltageStatusEnum voltageStatus = CodeDescEnumHelper.getEnumTypeByCode(CardEnum.VoltageStatusEnum.class, cardCondition.getVoltageStatus());
                predicates.add(cb.equal(root.get(CardPO_.voltageStatus), voltageStatus));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public CardPO save(BaseSaveDTO saveDTO) {
        CardSaveDTO cardSaveDTO = (CardSaveDTO) saveDTO;
        CardPO cardPO = findById(cardSaveDTO.getCardId());
        //根据卡号获取卡PO
        CardPO noCardPO = repository.findByCardNo(cardSaveDTO.getCardNo());
        //新增判断卡号是否存在
        if (cardPO == null) {
            if (noCardPO != null && !noCardPO.isEnable()) {
                throw new IllegalStateException("卡号已经存在");
            }
            cardPO = new CardPO();
            cardPO.setCardId(noCardPO != null ? noCardPO.getCardId() : null);
            cardPO.setStatus(false);
            cardPO.setVoltageStatus(CardEnum.VoltageStatusEnum.STATUS_0);
            cardPO.setEnable(true);
            cardPO.setDeleteStatus(false);
        } else {
            if (noCardPO != null && noCardPO.getCardId() != cardPO.getCardId()) {
                throw new IllegalStateException("卡号已经存在");
            }
        }
        cardPO.setCardNo(cardSaveDTO.getCardNo());
        CardEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(CardEnum.TypeEnum.class, cardSaveDTO.getType());
        cardPO.setType(type);
        cardPO.setVersion(cardSaveDTO.getVersion());
        cardPO.setEnable(true);
        cardPO = repository.save(cardPO);
        //将卡缓存到redis中
        redisTemplate.opsForHash().put(RedisConstant.KEY_CARD, "card_" + cardPO.getCardNo(), new RedisCardDTO(cardPO));
        return cardPO;
    }

    @Override
    public boolean updateEnable(Integer cardId) {
        CardPO cardPO = findById(cardId);
        if (cardPO != null) {
            repository.updateEnableById(cardId, !cardPO.isEnable());
            //覆盖缓存
            cardPO.setEnable(!cardPO.isEnable());
            redisTemplate.opsForHash().put(RedisConstant.KEY_CARD, "card_" + cardPO.getCardNo(), cardPO);
        }
        return true;
    }

    @Override
    public CardPO find(Long cardNo) {
        return repository.findByCardNo(cardNo);
    }

    @Override
    public boolean unbinding(Long cardNo) {
        repository.unbinding(cardNo);
        //覆盖缓存
        CardPO cardPO = repository.findByCardNo(cardNo);
        redisTemplate.opsForHash().put(RedisConstant.KEY_CARD, "card_" + cardPO.getCardNo(), new RedisCardDTO(cardPO));
        return true;
    }

    @Override
    public boolean updateDeleteStatus(Integer cardId) {
        CardPO cardPO = findById(cardId);
        if (cardPO.getUser() != null) {
            throw new IllegalStateException("该卡已被绑定，请先解绑");
        }
        repository.updateDeleteStatus(cardId);
        //缓存中删除掉工卡
        redisTemplate.opsForHash().delete(RedisConstant.KEY_CARD, "card_" + cardPO.getCardNo());
        return true;
    }

    @Override
    public void lead(MultipartFile updateFile) throws IOException {
        POIFSFileSystem fs = new POIFSFileSystem(updateFile.getInputStream());
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fs);
        List<List<ExcelHelper.CellDesc>> excelContent = ExcelHelper.readWorkbook(hssfWorkbook, "sheet1", 1, ExcelConstant.CARD.length, 0);
        List<CardPO> cardlist = new ArrayList<>();
        if (excelContent != null) {
            for (List<ExcelHelper.CellDesc> r : excelContent) {
                if (r.get(0).getValue() == null) {
                    continue;
                }
                if (StringUtils.isEmpty(r.get(0).getValue().toString())) {
                    continue;
                }
                long cardNo = Long.parseLong(r.get(0).getValue().toString().trim());
                CardPO cardPO = find(cardNo);
                if (cardPO == null) {
                    cardPO = new CardPO();
                    cardPO.init();
                }
                cardPO.setCardNo(cardNo);
                cardPO.setVersion(r.get(2).getValue().toString().trim());
                cardPO.setType(CodeDescEnumHelper.getEnumTypeByCode(CardEnum.TypeEnum.class, Integer.parseInt(r.get(1).getValue().toString().trim())));
                cardlist.add(cardPO);
            }
        }
        save(cardlist);
    }

    @Override
    public void updateVoltageStatus(Long cardNo, CardEnum.VoltageStatusEnum voltageStatusEnum) {
        //覆盖掉缓存
        CardPO cardPO = repository.findByCardNo(cardNo);
        cardPO.setVoltageStatus(voltageStatusEnum);
        redisTemplate.opsForHash().put(RedisConstant.KEY_CARD, "card_" + cardPO.getCardNo(), new RedisCardDTO(cardPO));

        repository.updateVoltageStatusById(cardNo, voltageStatusEnum.getCode());
    }
}
